package com.unionftech.common.utils;

import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class LogWatcher {

    public static final String TAG = LogWatcher.class.getSimpleName();

    private static volatile LogWatcher instance = null;

    private static final String LOG_FILE_PREFIX = "logcat_";
    private static final String LOG_FILE_SUFFIX = ".txt";

    private static String sLogDirPath;

    private Context mContext;

    private Process mLogcatProcess;

    private File mLogcatFile;

    private LogWatcher() {
    }

    public static LogWatcher getInstance() {
        if (instance == null) {
            synchronized (LogWatcher.class) {
                if (instance == null) {
                    instance = new LogWatcher();
                }
            }
        }
        return instance;
    }

    /**
     * Init the logcat watcher.
     *
     * @param context    Application context.
     * @param logDirName Logcat save dir
     * @return LogcatWatcher instance.
     */
    public LogWatcher init(Context context, String logDirName) {
        if (context == null)
            throw new IllegalArgumentException("LogWatcher: init failed, context can not be null");

        if (TextUtils.isEmpty(logDirName))
            throw new IllegalArgumentException("LogWatcher: init failed, logDirName can not be null");

        this.mContext = context.getApplicationContext();
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            File documentFileDir = mContext.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
            if (documentFileDir != null) {
                sLogDirPath = documentFileDir.getAbsolutePath() + File.separator + logDirName;
            } else {
                Log.e(TAG, "LogWatcher: init LogWatcher failed!");
            }
        } else {
            sLogDirPath = mContext.getFilesDir().getAbsolutePath() + File.separator + logDirName;
        }

        return this;
    }

    /**
     * Start capture the logcat generated by the app.
     */
    public void startWatch() {
        stopWatch();

        if (TextUtils.isEmpty(sLogDirPath)) {
            Log.e(TAG, "LogWatcher: can not watch log, the log dir can not be created");
            return;
        }

        mLogcatFile = createNewLogFile();
        if (mLogcatFile == null) {
            Log.e(TAG, "LogWatcher: can not create new log file");
            return;
        } else {
            Log.i(TAG, "LogWatcher: log file save path >>> " + mLogcatFile.getAbsolutePath());
        }

        // Clear cache log
        try {
            Process process = Runtime.getRuntime().exec("logcat -c");
            process.destroy();
        } catch (IOException e) {
            e.printStackTrace();
        }

        //final String LOGCAT_FILTER_CMD = "logcat -v time *:v | grep \"(" + android.os.Process.myPid() + ")\" > " + newLogFile.getAbsolutePath();
        final String LOGCAT_FILTER_CMD = "logcat -v time *:V -f " + mLogcatFile.getAbsolutePath();

        try {
            mLogcatProcess = Runtime.getRuntime().exec(LOGCAT_FILTER_CMD);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Stop capture the logcat generated by the app.
     */
    public void stopWatch() {
        if (mLogcatProcess != null) {
            mLogcatProcess.destroy();
            mLogcatProcess = null;
        }

        if (mLogcatFile != null) {
            notifySystemToScan(mContext, mLogcatFile);
        }
    }

    private File createNewLogFile() {
        File logSaveDir = new File(sLogDirPath, getCurrentDateStr());
        if (!logSaveDir.exists()) {
            boolean mkdirs = logSaveDir.mkdirs();
            if (!mkdirs) {
                Log.e(TAG, "LogWatcher: create new save dir failed");
                return null;
            }
        }

        String logFileName = LOG_FILE_PREFIX + getCurrentTimeStr() + LOG_FILE_SUFFIX;
        File logFile = new File(logSaveDir, logFileName);

        try {
            boolean createRet = logFile.createNewFile();
            if (!createRet) {
                Log.e(TAG, "LogWatcher: create new log file failed");
                return null;
            }
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }

        return logFile;
    }

    private static String getCurrentTimeStr() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", Locale.getDefault());
        return sdf.format(new Date(System.currentTimeMillis()));
    }

    private static String getCurrentDateStr() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
        return sdf.format(new Date(System.currentTimeMillis()));
    }

    private static void notifySystemToScan(Context context, File file) {
        if (context == null || file == null) return;
        Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        Uri uri = Uri.fromFile(file);
        intent.setData(uri);
        context.sendBroadcast(intent);
    }
}
